#include "buttons.h"
#include "lcd1602.h"
#include "public.h"
#include "uart.h"

static u8 text[17]    = {0};
static u8 datas[10]   = {0};
static u8 is_1s_fresh = 1;

/* 占空比 0-1000 */
volatile u16 duty_cycle = 0;
/* 电池最大容量：Wh，默认为 30k Wh */
static u32 capacity_max = 30000000;
// #define capacity_max 30000000
/* 当前容量：Wh */
static u32 capacity = 0;
/* 百分比电量 0-10000 */
static u16 quantity = 0;
/* 电池内阻：毫欧 */
static u32  _resister = 100;
static u16 *resister  = (u16 *)&_resister;
/* 电池电动势，分度：0.1 V */
volatile u16 voltage = 6850;
/* 当前的充电电压，分度：0.1 V */
static u16 charge_voltage = 0;
/* 当前的充电电流，分度：1 A */
volatile u16 amper = 0;

/* 三个设置项 */
static u32 *settings_value[3] = {&capacity_max, &capacity, (u32 *)&_resister};

void
load_info1(void)
{
        u16 temp = quantity;
        u8  num  = 0;
        text[15] = '%';
        //
        const u8 __code *text_process = "Process:";
        for (signed char i = 14; i >= 0; --i) {
                if (i == 12) {
                        text[i] = '.';
                        continue;
                }
                num = temp % 10 + '0';
                if (temp > 0) {
                        text[i] = num;
                        temp /= 10;
                } else if (i >= 11) {
                        text[i] = '0';
                } else if (i <= 7) {
                        text[i] = text_process[i];
                } else {
                        text[i] = ' ';
                }
        }
}

void
load_info2(void)
{
        u16 temp = duty_cycle;
        u8  num  = 0;
        //
        const u8 __code *text_duty = "Duty Cycle:";
        for (signed char i = 15; i >= 0; --i) {
                num = temp % 10 + '0';
                if (temp > 0) {
                        text[i] = num;
                        temp /= 10;
                } else if (i == 15) {
                        text[i] = '0';
                } else if (i <= 10) {
                        text[i] = text_duty[i];
                } else {
                        text[i] = ' ';
                }
        }
}

void
load_info3(void)
{
        u16 temp = voltage;
        u8  num  = 0;
        //
        const u8 __code *text_voltage = "Voltage:";
        for (signed char i = 15; i >= 0; --i) {
                if (i == 14) {
                        text[i] = '.';
                        continue;
                }
                num = temp % 10 + '0';
                if (temp > 0) {
                        text[i] = num;
                        temp /= 10;
                } else if (i >= 11) {
                        text[i] = '0';
                } else if (i <= 7) {
                        text[i] = text_voltage[i];
                } else {
                        text[i] = ' ';
                }
        }
}

void
settings(void)
{
        u8 pages  = 0;
        u8 status = 1;
        u8 btn    = BUTTON_TYPE_NONE;
        //
        const u8 __code *pages_title[3] = {"Max capacity:   ",
                                           "Now capacity:   ",
                                           "Resister set:   "};

settings_loop:

        if (pages >= 3) {
                if (*resister == 0)
                        *resister = 100;
                if (capacity_max < 100000) {
                        capacity_max = 100000;
                        capacity     = 0;
                }
                return;
        }

        btn = buttons_get();

        if (btn == BUTTON_TYPE_RETURN)
                return;

        switch (status) {
        case 0:
                if (btn <= 9) {
                        *settings_value[pages] =
                                *settings_value[pages] * 10 + btn;
                        if (pages == 2 && *resister > 1000)
                                *settings_value[pages] /= 10;
                        if (pages == 1 && capacity > capacity_max)
                                *settings_value[pages] /= 10;
                        status = 1;
                } else if (btn == BUTTON_TYPE_DELETE) {
                        *settings_value[pages] /= 10;
                        status = 1;
                } else if (btn == BUTTON_TYPE_PAGE_UP) {
                        if (pages == 0)
                                break;
                        pages -= 1;
                        status = 1;
                } else if (btn == BUTTON_TYPE_PAGE_NEXT) {
                        pages += 1;
                        status = 1;
                }
                break;
        case 1:
                lcd1602_show_string(0, pages_title[pages]);
                u32 temp = *settings_value[pages];
                for (signed char i = 15; i >= 0; --i) {
                        if (temp > 0) {
                                text[i] = temp % 10 + '0';
                                temp /= 10;
                        } else {
                                if (i == 15)
                                        text[i] = '0';
                                else
                                        text[i] = ' ';
                        }
                }
                lcd1602_show_string(1, text);
                status = 0;
                break;
        default:
                break;
        }

        goto settings_loop;
}

void
main(void)
{
        lcd1602_init();
        uart_init(0xfd); // 19200

        u8 counter = 0;
        u8 button  = BUTTON_TYPE_NONE;

loop_main:
        button = buttons_get();
        if (button == BUTTON_TYPE_SETTINGS)
                settings();

        if (counter % 20 == 0) {
                is_1s_fresh = counter / 20;
                if (counter >= 120)
                        counter = 0;
        }
        counter += 1;

        EA = 0;
        capacity += duty_cycle * 25 / 18;
        if (capacity > capacity_max)
                capacity = capacity_max;
        /* 更新充电百分比: 0-10000 * 0.01% */
        quantity = capacity / (capacity_max / 10000);
        /* 更新电池电动势 */
        voltage = 6850 + capacity / (capacity_max / 1150);
        /* 更新充电电压: 6850-8000 * 0.1V */
        charge_voltage = voltage + duty_cycle / (voltage / (u16)*resister);
        /* 更新充电电流 */
        amper = duty_cycle * 10 / (charge_voltage / 100);
        // amper = (charge_voltage - voltage) * 100 / (u16)resister;
        EA = 1;

        /* 写入当前电量百分比 */
        u8 *p = tx_buf, num = 0;
        u16 temp = quantity, i;
        for (i = 10000; i > 0; i /= 10) {
                num = temp / i;
                temp -= num * i;
                *p++ = num + '0';
        }
        *p++ = ',';
        temp = charge_voltage;
        for (i = 1000; i > 0; i /= 10) {
                num = temp / i;
                temp -= num * i;
                *p++ = num + '0';
        }
        *p++ = ',';
        temp = amper;
        for (i = 1000; i > 0; i /= 10) {
                num = temp / i;
                temp -= num * i;
                *p++ = num + '0';
        }
        *p = '\0';

        uart_send();

        if (is_1s_fresh) {
                if (is_1s_fresh % 3 == 1)
                        lcd1602_clear();
                load_info1();
                lcd1602_show_string(0, text);
                if (is_1s_fresh <= 3)
                        load_info2();
                else
                        load_info3();
                lcd1602_show_string(1, text);
                is_1s_fresh = 0;
        }

        delay_ms(20);
        goto loop_main;
}

void
uart_handler(void) __interrupt(4)
{
        static u8 state = 0;
        static u8 index = 0;

        if (TI) {
                TI = 0;
                if (tx_index < tx_len)
                        SBUF = tx_buf[tx_index++];
                else
                        tx_len = 0; // 发送完成
                return;
        }

        RI = 0;
        //
        u8 data = SBUF;
        if (state == 0) {
                if (data == '\r') {
                        state = 2;
                } else {
                        state          = 1;
                        datas[index++] = data;
                }
        } else if (state == 1) {
                if (data == '\r')
                        state = 2;
                else
                        datas[index++] = data;
        } else if (state == 2) {
                if (data == '\n')
                        state = 0;
                datas[index] = '\0';
                index        = 0;
                if (datas[0] != '\0' && state == 0) {
                        duty_cycle = 0;
                        for (u8 i = 0; datas[i] != '\0'; ++i)
                                duty_cycle = duty_cycle * 10 + (datas[i] - '0');
                        if (duty_cycle > 1000)
                                duty_cycle = 1000;
                } else {
                        state = 0;
                        index = 0;
                }
        }
        if (index >= 9) {
                datas[9] = '\0';
                index    = 0;
                state    = 0;
        }
}
